package com.revai.engine.basic.service.impl;

import com.revai.engine.basic.service.BasicService;
import com.revai.engine.basic.util.StrUtils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.yaml.snakeyaml.Yaml;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Service
public class BasicServiceImpl implements BasicService {

  private final Logger logger = LoggerFactory.getLogger(BasicServiceImpl.class);

  @Value("${spring.engine.project.path}")
  private String PREJECT_PATH;

  private Map<String, Object> metaConfigs;

  /**
   * 获取文件流
   * @param file
   * @return
   */
  private InputStream getInputStream(String file) throws FileNotFoundException {
    if (PREJECT_PATH == null || "".equals(PREJECT_PATH.trim())) {
      ClassLoader classLoader = getClass().getClassLoader();
      return classLoader.getResourceAsStream("project" + "/" + (file.replaceAll("^\\./|^/", "")));
    } else {
      Path path = Paths.get(PREJECT_PATH, file);
      return new FileInputStream(path.toFile());
    }
  }

  /**
   * 系统启动时，读取并初始化meta配置
   */
  public void initMetaConfig() throws FileNotFoundException {
    Yaml yaml = new Yaml();
    InputStream iStream = getInputStream("/meta.yaml");
    Map<String, Object> data = yaml.load(iStream);
    parseYaml(data);
    logger.info("meta.yaml");
    metaConfigs = data;
  }

  /**
   * 查询meta配置
   */
  public Map getConfig() {
    return metaConfigs;
  }

  // 递归转换yaml
  private void parseYaml(Object data) {
    if (data instanceof List) {
      List list = (List) data;
      for (int i = 0; i < list.size(); i++) {
        if (list.get(i) != null && list.get(i) instanceof Object) {
          parseYaml(list.get(i));
        }
      }
    } else if (data instanceof Map) {
      Map<String, Object> map = (Map<String, Object>) data;

      Object page = null;
      Object relations = null;
      Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
      while (iterator.hasNext()) {
        Map.Entry<String, Object> entry = iterator.next();
        String key = entry.getKey();
        Object value = entry.getValue();

        String[] tempstrs = { "components", "template", "meta", "page" };
        if (Arrays.asList(tempstrs).contains(key) && value != null
            && value instanceof String) {
          try {
            InputStream iStream = getInputStream(value.toString());
            Yaml yaml = new Yaml();
            Map<String, Object> ydata = yaml.load(iStream);
            // table引用，合并standard_operations到operations
            if ("meta".equals(key) && value instanceof String
                && StrUtils.getTablePath(value.toString()).startsWith("table")) {
              // standard_operations
              Yaml oYaml = new Yaml();
              InputStream oStream = getInputStream("/table/standard_operations.yaml");
              List<Map<String, Object>> standardOperations = (List<Map<String, Object>>) oYaml.load(oStream);
              List<Map<String, Object>> operations = (List<Map<String, Object>>) ydata.get("operations");
              if (operations == null) {
                operations = new ArrayList<>();
              }
              List<Map<String, Object>> mergedList = Stream.concat(standardOperations.stream(), operations.stream())
                  .collect(Collectors.toList());
              List<Map<String, Object>> distinctList = mergedList.stream()
                  .collect(Collectors.toMap(
                      m -> m.get("key"),
                      Function.identity(),
                      (oldValue, newValue) -> newValue,
                      HashMap::new))
                  .values()
                  .stream()
                  .collect(Collectors.toList());
              if (Boolean.TRUE.equals(ydata.get("standard_operations"))) {
                ydata.put("operations", distinctList);
              }
            }
            // page模板配置
            if ("page".equals(key) && value instanceof String
                && StrUtils.getTablePath(value.toString()).startsWith("page")) {
              InputStream pageStream = getInputStream(value.toString());
              Yaml pageYaml = new Yaml();
              Map<String, Object> pageData = pageYaml.load(pageStream);
              if (pageData != null) {
                if (pageData.get("page") != null) {
                  // map.put("page", pageData.get("page"));
                  page = pageData.get("page");
                } else {
                  // map.remove("page");
                  iterator.remove();
                }
                if (pageData.get("relations") != null) {
                  relations = pageData.get("relations");
                  // map.put("relations", pageData.get("relations"));
                }
              }
            } else {
              parseYaml(ydata);
              map.put(key, ydata);
            }
          } catch (FileNotFoundException e) {
            e.printStackTrace();
            Map<String, Object> emptyMap = new HashMap<String, Object>();
            map.put(key, emptyMap);
            System.err.println(e.getMessage());
          }
        } else if (value instanceof Object) {
          parseYaml(value);
        }
      }
      if (page != null) {
        map.put("page", page);
      }
      if (relations != null) {
        map.put("relations", relations);
      }
    }
  }
}
